package org.timeismoney.payment.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.timeismoney.payment.common.PageBean;
import org.timeismoney.payment.dao.GenericDao;

/**
 * @author sidl
 * 
 * @param <E>
 *            Entity
 * @param <I>
 */
public class GenericDaoImpl<E, I extends Serializable> extends
		HibernateDaoSupport implements GenericDao<E, I> {

	protected Class<E>	clazz;

	public void setClazz(Class<E> clazz) {
		this.clazz = clazz;
	}

	@SuppressWarnings("unchecked")
	public I save(E e) {
		return (I) getHibernateTemplate().save(e);
	}

	public void update(E e) {
		getHibernateTemplate().update(e);
	}

	public void merge(E e) {
		getHibernateTemplate().merge(e);
	}

	public void delete(E e) {
		getHibernateTemplate().delete(e);
	}

	public void deleteAll(Collection<E> entities) {
		getHibernateTemplate().deleteAll(entities);
	}

	@SuppressWarnings("unchecked")
	public List<E> findByExample(E e) {
		return getHibernateTemplate().findByExample(e);
	}

	@SuppressWarnings("unchecked")
	public PageBean<E> findByExample(final E e, final PageBean<E> page) {
		return (PageBean<E>) getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Criteria c = session.createCriteria(clazz);
						c.add(Example.create(e));
						if (page.getSortColumnName() != null
								&& page.getSortDirection() != null) {
							c.addOrder(PageBean.SORT_DESC.equals(page
									.getSortDirection()) ? Order.desc(page
									.getSortColumnName()) : Order.asc(page
									.getSortColumnName()));
						}
						// 总页数
						List<E> list = c.list();
						page.setTotalRows(list.size());
						c.setFirstResult((page.getCurrentPage() - 1)
								* page.getRowsPerPage());
						c.setMaxResults(page.getRowsPerPage());
						page.setItems(list);
						return page;
					}
				});
	}

	@SuppressWarnings("unchecked")
	public E getEntity(I i) {
		return (E) getHibernateTemplate().get(clazz, i);
	}

	@SuppressWarnings("unchecked")
	public List<E> getEntitys() {
		return getHibernateTemplate().loadAll(clazz);
	}

	@SuppressWarnings("unchecked")
	public List<E> find(String queryString, Object... params) {
		if (params != null && params.length > 0) {
			return getHibernateTemplate().find(queryString, params);
		} else {
			return getHibernateTemplate().find(queryString);
		}
	}

	@SuppressWarnings("unchecked")
	public PageBean<E> find(final String queryString, final PageBean<E> page,
			final Object... params) {

		return (PageBean<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(queryString);
						if (params != null && params.length > 0) {
							for (int i = 0; i < params.length; i++) {
								query.setParameter(i, params[i]);
							}
						}
						// 获得总记录数
						int totalRows = getTotalRows(queryString, params);
						// 每页第一条记录
						query.setFirstResult((page.getCurrentPage() - 1)
								* page.getRowsPerPage());
						// 设置每页的显示条数
						query.setMaxResults(page.getRowsPerPage());
						// 获得每页显示的内容
						List<E> items = query.list();
						// 将数据封装到PageBean返回
						page.setItems(items);
						page.setTotalRows(totalRows);
						return page;
					}
				});
	}

	/**
	 * 拆分拼凑HQL，获得结果
	 * 
	 * @param queryString
	 * @return
	 */
	protected int getTotalRows(String queryString, final Object... params) {
		if (queryString.indexOf("from") == -1)
			return 0;
		final String hql = "select count(*) "
				+ queryString.substring(queryString.indexOf("from")).replace("left join fetch", "left join");

		return ((Long) getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (params != null && params.length > 0) {
					if (params != null || params.length > 0) {
						for (int i = 0; i < params.length; i++) {
							query.setParameter(i, params[i]);
						}
					}
				}
				return query.uniqueResult();
			}
		})).intValue();
	}

	@SuppressWarnings("unchecked")
	public PageBean<E> find(final PageBean<E> page) {

		return (PageBean<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Criteria criteria = session.createCriteria(clazz);
						// 获得总记录数
						int totalRows = getTotalRows();
						// 每页第一条记录
						criteria.setFirstResult((page.getCurrentPage() - 1)
								* page.getRowsPerPage());
						// 设置每页的显示条数
						criteria.setMaxResults(page.getRowsPerPage());
						if (page.getSortColumnName() != null
								&& page.getSortDirection() != null) {
							criteria.addOrder(PageBean.SORT_DESC.equals(page
									.getSortDirection()) ? Order.desc(page
									.getSortColumnName()) : Order.asc(page
									.getSortColumnName()));
						}
						// 获得每页显示的内容
						List<E> items = criteria.list();
						// 将数据封装到PageBean返回
						page.setItems(items);
						page.setTotalRows(totalRows);
						return page;
					}

				});
	}

	private int getTotalRows() {
		final String hql = "select count(*) from " + clazz.getName();

		return ((Long) getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				return query.uniqueResult();
			}
		})).intValue();
	}
}
